package com.yxn.cloud.ware.listener;

import com.alibaba.fastjson.TypeReference;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.cloud.common.constant.OrderStatus;
import com.cloud.common.to.mq.StockDetailTo;
import com.cloud.common.to.mq.StockLockTo;
import com.cloud.common.utils.R;
import com.rabbitmq.client.Channel;
import com.yxn.cloud.ware.dao.WareSkuDao;
import com.yxn.cloud.ware.entity.WareOrderTaskDetailEntity;
import com.yxn.cloud.ware.entity.WareOrderTaskEntity;
import com.yxn.cloud.ware.service.WareOrderTaskDetailService;
import com.yxn.cloud.ware.service.WareOrderTaskService;
import com.yxn.cloud.ware.service.WareSkuService;
import com.yxn.feign.OrderFeignService;
import com.cloud.common.to.mq.OrderVo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.RabbitHandler;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;

/**
 * @author lisw
 * @create 2021/8/15 16:18
 */
@Service
@RabbitListener(queues = "stock.release.stock.queue")
public class StockReleaseListener {
    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Resource
    RabbitTemplate rabbitTemplate;

    @Resource
    WareSkuDao wareSkuDao;

    @Resource
    WareOrderTaskDetailService wareOrderTaskDetailService;

    @Resource
    WareOrderTaskService wareOrderTaskService;

    @Resource
    OrderFeignService orderFeignService;

    /**
     * 1、锁定失败。前面的工作单信息就回滚了。发送出去的消息。即使要解锁记录，去数据库中查不到id。
     * <p>
     * 一定要关闭自动确认机制，因为有可能我们的解锁库存出现了异常，而导致消息消费失败。
     *
     * @param to
     * @param message
     */
    @RabbitHandler
    public void handleReleaseStock(StockLockTo to, Message message, Channel channel) throws IOException {
        logger.info("收到的库存延时消息是： {}", to);
        Long wareTaskId = to.getWareTaskId();
        StockDetailTo stockDetailTo = to.getStockDetailTo();

        //解锁
        //1、查询数据库关于这个订单的锁定库存信息。没有：库存锁定失败了，库存整体回滚了，此时无需回滚。反之则需要
        Long detailId = stockDetailTo.getId();
        WareOrderTaskDetailEntity detailEntity = wareOrderTaskDetailService.getById(detailId);
        if (null != detailEntity) {
            //解锁逻辑
            /**如果有订单明细，但是没有订单，同时没有采用分布式事务，这时就要去看订单是否存在
             * 有可能存在订单明细存在，但是订单有可能出现了异常，此时也不需要进行解锁。
             * 如果订单存在，那么就要看订单的状态
             *      订单取消的话，那么也要解锁库存。
             *      订单不取消，那么就不需要解锁库存。
             * */
            WareOrderTaskEntity taskEntity = wareOrderTaskService.getById(wareTaskId);
            //根据订单号来查询对应的订单状态
            String orderSn = taskEntity.getOrderSn();
            R r = orderFeignService.getOrderStatusByOrderSn(orderSn);
            if (r.getCode() == 0) {
                //订单数据返回成功
                OrderVo order = r.getData(new TypeReference<OrderVo>() {
                });
                if ((null == order) || (OrderStatus.IS_CLOSED.getStatus().equals(order.getStatus()))) {
                    if (detailEntity.getLockStatus() == 1) {
                        //订单已被关闭，需要解锁库存
                        unLockStock(stockDetailTo.getSkuId(), stockDetailTo.getWareId(),
                                stockDetailTo.getSkuNum(), wareTaskId);
                        channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
                    }
                }
            } else {
                //如果返回状态不为0，那么就直接拒绝消费，但是要重新放到队列里面。让其他服务进行消费。因为有可能是服务的问题
                rejectMessage(message, channel);
            }
        } else {
            //无需解锁
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        }
    }

    private void unLockStock(Long skuId, Long wareId, Integer skuNum, Long wareTaskId) {
        wareSkuDao.unLockStock(skuId, wareId, skuNum);
        //更新订单详情页的锁定状态
        WareOrderTaskDetailEntity detailEntity = new WareOrderTaskDetailEntity();
        detailEntity.setId(wareTaskId);
        //2为已解锁
        detailEntity.setLockStatus(2);
        wareOrderTaskDetailService.updateById(detailEntity);
    }


    @RabbitHandler
    public void handleOrderCloseRelease(OrderVo orderVo, Message message, Channel channel) {
        logger.info("订单关闭，准备解锁库存, orderVo:{}", orderVo);
        try {
            unLockStock(orderVo);
            channel.basicAck(message.getMessageProperties().getDeliveryTag(), false);
        } catch (Exception e) {
            rejectMessage(message, channel);
        }
    }

    private void unLockStock(OrderVo orderVo) {
        //更新订单详情页的锁定状态,防止订单服务卡顿，出现永远不能解锁库存的现象
        //查一下最新的解锁状态，防止重复解锁库存
        String orderSn = orderVo.getOrderSn();
        WareOrderTaskEntity taskEntity = wareOrderTaskService.getOrderTaskByOrderSn(orderSn);
        Long taskId = taskEntity.getId();
        //按照库存工作单Id，找到所有的未解锁的详情
        List<WareOrderTaskDetailEntity> list = wareOrderTaskDetailService.list(new QueryWrapper<WareOrderTaskDetailEntity>()
                .eq("task_id", taskId)
                .eq("lock_status", 1));
        for (WareOrderTaskDetailEntity detailEntity : list) {
            unLockStock(detailEntity.getSkuId(),
                    detailEntity.getWareId(),
                    detailEntity.getSkuNum(),
                    detailEntity.getTaskId());
        }
    }

    private void rejectMessage(Message message, Channel channel) {
        try {
            channel.basicReject(message.getMessageProperties().getDeliveryTag(), true);
        } catch (IOException e) {
            logger.info("消息拒绝异常，e : {}", e);
        }
    }

}
